package com.bear.newsset.util;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Service;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.Process;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import androidx.core.content.FileProvider;
import android.widget.Toast;

import com.alibaba.fastjson.JSONObject;
import com.bear.newsset.R;
import com.bear.newsset.api.QueryAppVerApi;
import com.bear.newsset.api.UpdateFileApi;
import com.bear.newsset.entity.RequesVersionEntity;
import com.bear.newsset.entity.VersionEntity;
import com.bear.newsset.service.DownloadService;
import com.ybear.networkutil.HttpUtil;

import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

import static com.bear.newsset.util.AppUtil.EXIT_TYPE.ACTIVITY;
import static com.bear.newsset.util.AppUtil.EXIT_TYPE.ALL;
import static com.bear.newsset.util.AppUtil.EXIT_TYPE.SERVICE;
import static com.bear.newsset.util.SysUtil.getPackgeInfo;

/**
 *
 * @see #getAppName(Context)
 * @see #getVerName(Context)
 * @see #getVerCode(Context)
 * @see #getSdkVer()
 * @see #doubleBackPressedExit(Context)
 * @see #backPressedHome(Context)
 * @see #installApk(Context, File)
 * @see #downloadApk(Context)
 * @see #getCreateApkPath(Context)
 * @see #requestVersion(Context, CallBackCheckVersionListener)
 * @see #checkVersion(Context)
 *
 *
 * @see #exitStack(Object, boolean) //私有方法
 * @see #addExitStack(Activity)
 * @see #addExitStack(Service)
 * @see #removeExitStack(Activity)
 * @see #removeExitStack(Service)
 * @see #exitApp(EXIT_TYPE)
 * @see #exitApp()
 * @see #exitApp(long)
 * @see #exitActivityAll()
 * @see #exitServiceAll()
 * @see #exitActivity(Class[])
 * @see #exitKeepActivity(Class)
 * @see #isExistActivity(Class)
 * @see #reStartApp(Context, Class)
 * @see #reStartApp(Context, Class, long)
 */
public class AppUtil {
    //退出类型
    public enum EXIT_TYPE { ACTIVITY, SERVICE, ALL }
    private static Map<String, Object> exitAppMap;
    private static long firstTime = 0;

    public interface CallBackCheckVersionListener {
        void getVersion(VersionEntity verEntity, boolean isUpdate);
    }

    /**
     * 获取app名称
     * @param mContext      上下文
     * @return              返回
     */
    public static String getAppName(@NonNull Context mContext) {
        try {
            return mContext.getResources().getString(R.string.app_name);
        }catch (Exception e) {
            e.printStackTrace();
        }
        return "App";
    }

    /**
     * 获取版本名称
     * @param mContext  上下文
     * @return          返回版本名称
     */
    public static String getVerName(@NonNull Context mContext) {
        try {
            return Objects.requireNonNull(getPackgeInfo(mContext)).versionName;
        }catch (NullPointerException e) {
            e.printStackTrace();
        }
        return "获取失败";
    }

    /**
     * 获取版本代码
     * @param mContext  上下文
     * @return          返回版本代码
     */
    public static long getVerCode(@NonNull Context mContext) {
        PackageInfo pi;
        try {
            pi = Objects.requireNonNull(getPackgeInfo(mContext));
            return Build.VERSION.SDK_INT >= 28 ? pi.getLongVersionCode() : pi.versionCode;
        }catch (NullPointerException e) {
            e.printStackTrace();
        }
        return 0L;
    }

    /**
     * 获取当前SDK版本
     * @return  ver
     */
    public static int getSdkVer() {
        return Build.VERSION.SDK_INT;
    }

    /**
     * 双击退出app
     * @param mContext  上下文
     */
    @UiThread
    public static void doubleBackPressedExit(Context mContext) {
        String appName = getAppName(mContext);
        String showText = "再按一次退出" + appName;
        long secondTime = System.currentTimeMillis();
        if (secondTime - firstTime > 2000) {
            try {
                Toast.makeText(mContext, showText, Toast.LENGTH_SHORT).show();
            }catch (Exception e) {
                e.printStackTrace();
            }
            firstTime = secondTime;
        } else {
            exitApp();
        }
    }

    /**
     * 返回到桌面
     * @param mContext      上下文
     */
    public static void backPressedHome(@NonNull Context mContext) {
        Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        intent.addCategory(Intent.CATEGORY_HOME);
        mContext.startActivity(intent);
    }

    /**
     * 安装apk
     * @param mContext      上下文
     * @param file          安装的文件
     * @return              是否安装成功
     */
    public static boolean installApk(Context mContext, File file) {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        Uri uri;
        String processName;
        String type = "application/vnd.android.package-archive";
        int flag;
        if( file.exists() ) {
            if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ) {
                //7.0以上版本适配
                flag = Intent.FLAG_GRANT_READ_URI_PERMISSION;
                processName = mContext.getApplicationInfo().processName + ".fileProvider";
                LogUtils.d("TAG", "processName:" + processName);
                LogUtils.d("TAG", "filePath:" + file.getAbsolutePath());
                uri = FileProvider.getUriForFile(mContext, processName, file);
                intent.setDataAndType(uri, type);
            }else {//7.0以下版本
                flag = Intent.FLAG_ACTIVITY_NEW_TASK;
                intent.setDataAndType(Uri.fromFile(file), type);
            }
            intent.setFlags(flag);
            if( mContext.getPackageManager().queryIntentActivities(intent, 0).size() > 0 ) {
                mContext.startActivity(intent);
            }
            return true;
        }
        return false;
    }

    /**
     * 下载aok
     */
    public static void downloadApk(Context mContext) {
        String apkUrlPath = HttpUtil.fromatUrl( new UpdateFileApi() );
        String savePath;
        Intent intent = new Intent(mContext, DownloadService.class);

        savePath = getCreateApkPath(mContext);  //创建apk路径
        intent.putExtra("apkUrlPath", apkUrlPath);
        intent.putExtra("savePath", savePath);
        //打开服务下载更新的apk
        mContext.startService(intent);
    }

    /**
     * 获取创建apk完整的路径
     * @param mContext     上下文
     * @return
     */
    private static String getCreateApkPath(Context mContext) {
        String directory = Environment.getExternalStorageDirectory().getAbsolutePath();
        String path =  directory + "/download/" + mContext.getPackageName();
        File f = new File(path);
        boolean isMkdirs = true;
        //创建目录
        if( !f.exists() ) {
            isMkdirs = f.mkdirs();
            LogUtils.d("TAG", "下载目录不存在：创建目录结果(" + isMkdirs + ")");
        }
        //设置完整的目录
        if( isMkdirs ) {
            path += "/install.apk";
            LogUtils.d("TAG", "下载目录创建完毕：" + path);
        }
        return path;
    }

    /**
     * 请求版本信息
     * @param mCallBackCheckVersionListener     回调接口
     */
    private static void requestVersion(final Context mContext,
            final CallBackCheckVersionListener mCallBackCheckVersionListener) {

        QueryAppVerApi appVerApi = new QueryAppVerApi();

        appVerApi.setCallbackString(new HttpUtil.CallbackString() {
            @Override
            public void getRequestString(@Nullable String s) {
                RequesVersionEntity rvEntity = null;
                if( s != null && !s.equals("") ) {
                    LogUtils.d("TAG", "CheckVersion:" + s);
                    try {
                        rvEntity = JSONObject.parseObject(s, RequesVersionEntity.class);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    if( rvEntity != null && rvEntity.getStatus() == 200 ) {
                        long code = getVerCode(mContext);
                        boolean isUpdate = false;
                        //检查版本是否更新
                        if( rvEntity.getVersion().getCode() > code ) { isUpdate = true; }
                        mCallBackCheckVersionListener.getVersion(rvEntity.getVersion(), isUpdate);
                    }
                }
            }
        });
        HttpUtil.sendPostCallString(appVerApi);
    }

    /**
     * 检查版本
     */
    public static void checkVersion(final Context mContext) {
        //查询版本信息
        requestVersion(mContext, new CallBackCheckVersionListener() {
            @Override
            public void getVersion(VersionEntity verEntity, boolean isUpdate) {
                if( isUpdate ) {
                    //允许通过\n换行
                    String verInfo = verEntity.getVerInfo().replace("\\n", "\n");
                    String text = "最新版本：" + verEntity.getCodeName() + "\n" +
                            "当前版本：" + getVerName(mContext) + "\n\n" + verInfo;
                    final AlertDialog.Builder builder = new AlertDialog.Builder(mContext)
                            .setTitle("新版本提示")
                            .setMessage(text)
                            .setPositiveButton("更新", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialogInterface, int i) {
                                    downloadApk(mContext);
                                }
                            })
                            .setNegativeButton("暂不更新", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialogInterface, int i) {
                                    dialogInterface.dismiss();
                                }
                            });
                    //显示
                    ((Activity) mContext).runOnUiThread(builder::show);
                }
            }
        });
    }

    /**
     * 退出栈
     * @param obj       退出的activity/service
     * @param isAdd     true：添加，false：移除
     */
    private static void exitStack(@NonNull Object obj, boolean isAdd) {
        if( exitAppMap == null ) { exitAppMap = new HashMap<>(); }
        String key = obj.getClass().getSimpleName();
        boolean isExist = exitAppMap.containsValue(obj);
        if( isAdd ) {
            if( !isExist ) exitAppMap.put(key, obj);
        }else {
            if( isExist ) exitAppMap.remove( key );
        }
    }

    /**
     * 在退出栈中添加当前Activity
     * 调用exitApp后会退出栈中的所有Activity
     * @param mActivity     {@link Activity}
     * @param <T>           泛型必须继承{@link Activity}
     */
    public static <T extends Activity> void addExitStack(@NonNull T mActivity) {
        exitStack(mActivity, true);
    }

    /**
     * 在退出栈中添加当前Service
     * 调用exitApp后会退出栈中的所有Service
     * @param mService     {@link Service}
     * @param <T>           泛型必须继承{@link Service}
     */
    public static <T extends Service> void addExitStack(@NonNull T mService) {
        exitStack(mService, true);
    }

    /**
     * 在退出栈中移除当前Activity
     * @param mActivity     {@link Activity}
     * @param <T>           泛型必须继承{@link Activity}
     */
    public static <T extends Activity> void removeExitStack(@NonNull T mActivity) {
        exitStack(mActivity, false);
    }

    /**
     * 在退出栈中移除当前Service
     * @param mService      {@link Service}
     * @param <T>           泛型必须继承{@link Service}
     */
    public static <T extends Service> void removeExitStack(@NonNull T mService) {
        exitStack(mService, false);
    }
    /**
     * 退出app
     * 退出会以栈的形式退出
     */
    public static void exitApp(@NonNull EXIT_TYPE type) {
        boolean isAll = type.equals( ALL );
        boolean isA = type.equals( ACTIVITY );
        boolean isS = type.equals( SERVICE );
        for( Object obj : exitAppMap.values() ) {
            if( obj == null ) continue;
            if( (isAll || isA) && obj instanceof Activity ) ((Activity) obj).finish();
            if( (isAll || isS) && obj instanceof Service ) ((Service) obj).stopSelf();
        }
        if( isAll ) Process.killProcess( Process.myPid() );
    }

    /**
     * 退出整个app
     */
    public static void exitApp() { exitApp( ALL ); }

    /**
     * 延迟退出app
     * @param delayMillis   延迟毫秒
     */
    public static void exitApp(long delayMillis) {
        new Handler().postDelayed(() -> exitApp( ALL ), delayMillis);
    }

    /**
     * 退出所有Activity
     */
    public static void exitActivityAll() { exitApp( ACTIVITY ); }

    /**
     * 退出所有Service
     */
    public static void exitServiceAll() { exitApp( SERVICE ); }

    /**
     * 退出指定的Activity
     * @param clss   class
     */
    public static void exitActivity(@Nullable Class<?>... clss) {
        if( clss == null ) return;
        for( Class<?> cls : clss ) {
            if( cls == null ) continue;
            Object obj = exitAppMap.get(cls.getSimpleName());
            //当前Obj是否属于Activity
            if( obj instanceof Activity ) ( (Activity) obj ).finish();
        }
    }

    /**
     * 退出除了指定Activity之外的Activity
     * @param cls   class
     */
    public static void exitKeepActivity(@Nullable Class<?> cls) {
        if( cls == null ) return;
        for( String key : exitAppMap.keySet() ) {
            Object obj = exitAppMap.get( key );
            //当前Obj是否属于Activity，并且不是当前Activity
            if( obj instanceof Activity && !key.equals( cls.getSimpleName()) ) {
                ((Activity) obj).finish();
            }
        }
    }

    /**
     * 指定的activity/Service是否存在
     * @param cls   class
     * @return      是否存在
     */
    public static boolean isExistActivity(@Nullable Class<?> cls) {
        return cls != null && exitAppMap.containsKey( cls.getSimpleName() );
    }

    /**
     * 重启app
     * @param mContext  上下文
     */
    public static <A extends Activity> void reStartApp(@NonNull Context mContext, Class<A> cls) {
        Intent intent = new Intent(mContext, cls);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        mContext.startActivity(intent);
        Process.killProcess( Process.myPid() );
    }

    /**
     * 延迟重启app
     * @param mContext      上下文
     * @param delayMillis   延迟毫秒
     */
    public static <A extends Activity>
    void reStartApp(@NonNull Context mContext, Class<A> cls, long delayMillis) {
        new Handler().postDelayed(() -> reStartApp(mContext, cls), delayMillis);
    }
}
